package com.me.study.javaCore.classLoader.customClassLoader;

import org.apache.commons.lang3.StringUtils;
import sun.reflect.Reflection;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * ClassLoader：自定义 ClassLoader
 *
 * @author ME
 * @date 2021/3/9
 */
public class MyClassLoader extends ClassLoader {

    /** 指定使用自定义类加载器的包 */
    public static final String PREFIX = "com.me.study";

    /** 用来加载 JAVA官方类库的 JDK类加载器 */
    private final ClassLoader jdkClassLoader = this.getClass().getClassLoader();

    /** 缓存所有 路径 */
    private final Map<String, String> cache = new ConcurrentHashMap<>();

    /** 默认加载路径 */
    private final String classPath = Objects.requireNonNull(this.getClass().getClassLoader().getResource("")).getPath();

    public MyClassLoader() {
        super();
        // this.classPath = this.getClass().getClassLoader().getResource("").getPath();
    }

    /**
     * 重写 loadClass 方法来破坏双亲委派机制
     *
     * @param name className
     * @return 类对象
     * @throws ClassNotFoundException ClassNotFoundException
     */
    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        return loadClass(name, false);
    }

    /**
     * 重写 loadClass 方法来破坏双亲委派机制
     *
     * @param name      className
     * @param resolve   如果为 true，则解析该类
     * @return 类对象
     * @throws ClassNotFoundException ClassNotFoundException
     */
    @Override
    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
        // Class<?> result = null;
        // if (!name.startsWith(PREFIX)) {
        //     // 这里使用 默认的 JDK类加载器 加载 JAVA官方类库
        //     result = jdkClassLoader.loadClass(name);
        // }
        // if (result != null) {
        //     return result;
        // }
        //
        // byte[] classBytes = loadByte(name);
        // return defineClass(name, classBytes, 0, classBytes.length);

        Class<?> loadedClass = this.findLoadedClass(name);
        if (loadedClass == null) {
            try {
                loadedClass = this.findClass(name);
            } catch (ClassNotFoundException e) {
                loadedClass = this.getParent().loadClass(name);
            }
        }

        if (resolve) {
            this.resolveClass(loadedClass);
        }

        return loadedClass;
    }

    /**
     * 只重写当前方法的话，会受到双亲委派机制的影响，导致 内部引用的其他类（ClassB）被 AppClassLoader 加载
     *
     * @param name  className
     * @return 类对象
     * @throws ClassNotFoundException ClassNotFoundException
     */
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] classBytes = loadByte(name);
        return defineClass(name, classBytes, 0, classBytes.length);
    }

    /** 获取 .class 的字节流 */
    private byte[] loadByte(String name) throws ClassNotFoundException {
        String path;
        if (StringUtils.isBlank(path = cache.get(name))) {
            // path = classPath + name.replaceAll("\\.", "/") + ".class";
            path = classPath + name.replace('.', '/').concat(".class");
            cache.put(name, path);
        }
        byte[] data;
        try (FileInputStream fis = new FileInputStream(path)) {
            int len = fis.available();
            data = new byte[len];
            fis.read(data);
            if (data.length == 0) {
                throw new ClassNotFoundException();
            }
            return data;
        } catch (IOException e) {
            throw new ClassNotFoundException("类文件不存在", e);
        }
    }

}
